package com.boarsoft.boar.file.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.codehaus.plexus.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.boarsoft.agent.AgentService;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.BaseConfig;
import com.boarsoft.boar.app.AppFileBiz;
import com.boarsoft.boar.app.AppInstBiz;
import com.boarsoft.boar.entity.AppInst;
import com.boarsoft.boar.entity.FileInfo;
import com.boarsoft.boar.entity.FileVersion;
import com.boarsoft.boar.file.FileBiz;
import com.boarsoft.boar.file.FileVersionBiz;
import com.boarsoft.boar.service.FileService;
import com.boarsoft.common.Util;
import com.boarsoft.common.util.FileUtil;


public class FileServiceImpl implements FileService {
	public static final Logger log = LoggerFactory.getLogger(FileServiceImpl.class);

	@Autowired
	@Lazy(value = true)
	@Qualifier("agentX")
	private AgentService agentX;

	@Autowired
	private AppInstBiz appInstBiz;
	@Autowired
	private AppFileBiz appFileBiz;
	@Autowired
	private FileBiz fileBiz;
	@Autowired
	private FileVersionBiz fileVersionBiz;

	@Override
	public String getFilePath(FileVersion o) {
		// TODO 如果path是一个URL则从远程拉取

		// 读取本地存储
		StringBuilder sb = new StringBuilder(BaseConfig.PATH_PRIVATE);
		sb.append("/").append(o.getEnv());
		if (Util.strIsEmpty(o.getPath())) {
			return sb.append("/").append(o.getFileId())//
					.append("/").append(o.getId()).toString();
		}
		FileInfo fi = fileBiz.get(o.getFileId());
		return sb.append(o.getPath()).append(fi.getDeployPath()).toString();
	}

	@Override
	public String find(String ip, int port, String code) {
		AppInst ai = appInstBiz.find(ip, port);
		String appId = ai.getAppId();
		FileInfo fi = appFileBiz.find(appId, code);
		FileVersion v = fileVersionBiz.find(fi.getId(), ai.getEnv(), ai.getGroup());
		return this.getFilePath(v);
	}

	@Override
	public byte[] load(String fileId, String env, String group) throws IOException {
		FileVersion fv = fileVersionBiz.find(fileId, env, group);
		if (fv == null) {
			return null;
		}
		return this.read(fv);
	}

	@Override
	public byte[] load(String ip, int port, String code) throws IOException {
		String fp = this.find(ip, port, code);
		if (Util.strIsEmpty(fp)) {
			log.error("Can not find file {} for app inst {}:{}", code, ip, port);
			throw new IllegalStateException(String.format(//
					"Can not find %s for app inst %s:%d", code, ip, port));
		}
		return this.read(fp);
	}

	@Override
	public byte[] load(FileVersion o) throws IOException {
		if (o == null) {
			return null;
		}
		String fp = this.getFilePath(o);
		return this.read(fp);
	}

	private byte[] read(FileVersion o) throws IOException {
		String fp = this.getFilePath(o);
		return this.read(fp);
	}

	private byte[] read(String fp) throws IOException {
		File f = new File(fp);
		if (!f.exists()) {
			log.error("Can not find file {}", fp);
			throw new FileNotFoundException(fp);
		}
		log.info("Read bytes from file {}", fp);
		return FileUtil.readBytes(f);
	}

	@Override
	public ReplyInfo<Object> commit(String ip, int port, String code, byte[] bytes) throws IOException {
		AppInst ai = appInstBiz.find(ip, port);
		FileInfo fi = appFileBiz.find(ai.getAppId(), code);
		String fp = this.find(ip, port, code);
		// 查找当前激活的版本
		FileVersion a = fileVersionBiz.find(fi.getId(), ai.getEnv(), ai.getGroup());
		// 复制当前版本（新增版本）
		FileVersion v = FileVersion.clone(a);
		fileVersionBiz.save(v);
		// 写入文件
		log.warn("Writing file {} for file version {}", fp, v.getId());
		if (Util.strIsEmpty(fp)) {
			log.error("Can not find app inst {}:{}", ip, port);
			throw new IllegalStateException(String.format(//
					"Can not find app inst %s:%d", ip, port));
		}
		File f = new File(fp);
		if (!f.exists()) {
			FileUtils.mkdir(f.getParent());
		}
		FileUtil.writeBytes(f, bytes);
		// 修改当前版本状态为未激活
		a.setStatus(FileVersion.STATUS_INACTIVE);
		fileVersionBiz.save(a);
		// 激活新版本
		v.setStatus(FileVersion.STATUS_ACTIVE);
		fileVersionBiz.save(v);
		return new ReplyInfo<Object>(v);
	}

	@Override
	public ReplyInfo<Object> commit(String by, String fileId, String env, String group, byte[] bytes) {
		FileVersion ov = fileVersionBiz.find(fileId, env, group);
		FileVersion nv = FileVersion.clone(ov);
		fileVersionBiz.save(nv);
		String fp = this.getFilePath(nv);
		log.warn("Writing file {} for file version {}", fp, nv.getId());
		File f = new File(fp);
		try {
			if (FileUtil.makePath(f.getParent())) {
				FileUtil.writeBytes(f, bytes);
			} else {
				return new ReplyInfo<Object>("Can not make dir ".concat(f.getParent()));
			}
		} catch (IOException e) {
			log.error("Error on write file {}", fp, e);
			return new ReplyInfo<Object>(e.getMessage());
		}
		ov.setStatus(FileVersion.STATUS_INACTIVE);
		fileVersionBiz.save(ov);
		nv.setStatus(FileVersion.STATUS_ACTIVE);
		fileVersionBiz.save(nv);
		return new ReplyInfo<Object>(true, nv);
	}

	@Override
	public void delete(String fileId, String env, String group) {
		List<FileVersion> lt = fileVersionBiz.list(fileId, env);
		for (FileVersion o : lt) {
			String fp = this.getFilePath(o);
			FileUtil.deleteFile(fp);
		}
	}
}